// HSS.Logging.Program.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       Program.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Logging
{
	#region Using Directives
	using System;
	using System.Collections;
	using System.Diagnostics;
	using System.Globalization;
	using System.Reflection;
	using System.Runtime.InteropServices;
	using System.ServiceProcess;
	using System.Threading;
	using System.Windows.Forms;
	using System.ServiceModel;
	using System.ServiceModel.Description;
	#endregion

	static class Program
	{
		internal static string instanceId = "hsslogdebug{0EBBA454-7DA0-45c9-A6EC-1AD8C59C1C84}";
		internal static bool debug = false;
		internal static Mutex mutex;

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			Program.LogMessage("Main:Beginning");

			try
			{
				if (Debugger.IsAttached)
					debug = true;

				if (Environment.UserInteractive || debug)
					Program.RunDebugHost();
				else
					Program.RunServiceHost();
			}
			catch (Exception ex)
			{
				Program.LogException(ex.Message);
			}

			Program.LogMessage("Main:Ending");
		}

		[STAThread]
		private static void RunDebugHost()
		{
			Program.LogMessage("RunDebugHost:Beginning");

			if (Program.IsServiceRunning())
			{
				Program.LogMessage("RunDebugHost:Service Is Running, Debug can't start.");
				return;
			}

			mutex = new Mutex(true, instanceId);
			if (mutex.WaitOne(TimeSpan.Zero, true))
			{
				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);
				var serviceType = typeof(ILogServer);
				var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
				using (ServiceHost serviceHost = new ServiceHost(typeof(LogServer), new Uri(Log.HSSLogServerURI + "debug")))
				{
					serviceHost.AddServiceEndpoint(serviceType, binding, string.Empty);
					serviceHost.Open();
					Application.Run(new DebugHost());
					serviceHost.Close();
				}
				mutex.ReleaseMutex();
			}
			else
			{
				string msg = HSS.Logging.Resources.cantDebugMultiple;
				string tit = HSS.Logging.Resources.cantDebugServiceRunningTitle;
				Program.LateBoundMessageBoxShow(msg, tit);

				// send our Win32 message to make the currently running instance
				// jump on top of all the other windows
				NativeMethods.PostMessage(
					(IntPtr)NativeMethods.HWND_BROADCAST,
					NativeMethods.WM_SHOWME,
					IntPtr.Zero,
					IntPtr.Zero);

			}
			Program.LogMessage("RunDebugHost:Ending");

		}
		private static void RunServiceHost()
		{
			Program.LogMessage("RunServiceHost:Beginning");

			if (Program.IsDebugRunning())
				return;

			Program.debug = false;

			ServiceBase.Run(new LogService());

			Program.LogMessage("RunServiceHost:Ending");
		}
		private static bool IsServiceRunning()
		{
			if (Program.ServiceExist)
			{
				using (ServiceController svc = new ServiceController(HSS.Logging.Resources.logServiceName))
				{
					if (svc.Status != ServiceControllerStatus.Stopped)
					{
						string msg = HSS.Logging.Resources.cantDebugServiceRunning;
						string tit = HSS.Logging.Resources.cantDebugServiceRunningTitle;
						Program.LateBoundMessageBoxShow(msg, tit);
						return true;
					}
				}
			}

			return false;

		}
		private static bool ServiceExist
		{
			get
			{
				Microsoft.Win32.RegistryKey key = null;
				try
				{
					key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\" + HSS.Logging.Resources.logServiceName);
					if (null == key)
						return false;

					string imagePath = key.GetValue("ImagePath", "Missing") as string;
					if ("Missing" == imagePath)
						return false;

					imagePath = imagePath.Replace(@"""", string.Empty);
					if (System.IO.File.Exists(imagePath))
						return true;
					else
						return false;
				}
				finally
				{
					if (null != key)
						key.Close();
				}
			}
		}

		internal static void LogMessage(string Message)
		{
			if (!System.Diagnostics.Debugger.IsAttached)
				LogServer.WriteToMachineEventLog(Message, MachineEventLogSource.HSSLogService, EventLogEntryType.Information);
		}
		internal static void LogException(string Message)
		{
			if (!System.Diagnostics.Debugger.IsAttached)
				LogServer.WriteToMachineEventLog(Message, MachineEventLogSource.HSSLogService, EventLogEntryType.Error);
		}
		internal static bool IsDebugRunning()
		{
			return IsDebugRunning(true);
		}
		internal static bool IsDebugRunning(bool killProcess)
		{
			bool isDebugging = false;

			Program.LogMessage(string.Format("IsDebugRunning:Beginning:KillProcess={0}", killProcess));

			try
			{
				Process[] p = Program.GetProcessesByName(HSS.Logging.Resources.logServiceExe, ".");

				isDebugging = (null != p && p.Length > 1);

				if (isDebugging && killProcess)
				{
					int thisId = Process.GetCurrentProcess().Id;
					foreach (Process prc in p)
					{
						if (prc.Id != thisId)
							prc.Kill();
					}
					isDebugging = false;
				}
				if (isDebugging)
					Program.LogMessage(HSS.Logging.Resources.cantRunWhileDebugging);

			}
			catch (Exception ex)
			{
				Program.LogException(ex.Message);
			}
			finally
			{
				Program.LogMessage(string.Format("IsDebugRunning:Ending:DEBUG={0}", isDebugging));
			}

			return isDebugging;

		}
		internal static void LateBoundMessageBoxShow(string message, string title)
		{
			int num = 0;
			Type type = Type.GetType("System.Windows.Forms.MessageBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
			Type enumType = Type.GetType("System.Windows.Forms.MessageBoxButtons, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
			Type type3 = Type.GetType("System.Windows.Forms.MessageBoxIcon, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
			Type type4 = Type.GetType("System.Windows.Forms.MessageBoxDefaultButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
			Type type5 = Type.GetType("System.Windows.Forms.MessageBoxOptions, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
			type.InvokeMember("Show", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { message, title, Enum.ToObject(enumType, 0), Enum.ToObject(type3, 0), Enum.ToObject(type4, 0), Enum.ToObject(type5, num) }, CultureInfo.InvariantCulture);
		}
		internal static void TruncateLog()
		{
			try
			{
				LogServer server = new LogServer();
				server.TruncateLog();
				server = null;
			}
			catch { }
		}

		/// <summary>
		/// Creates an array of new <see cref="System.Diagnostics.Process"></see> components and associates 
		/// them with all the process resources on a remote computer that share the specified process name.
		/// </summary>
		/// <returns>An array of type <see cref="System.Diagnostics.Process"></see> that represents the process resources running the specified application or file.</returns>
		/// <param name="processName">The friendly name of the process. </param>
		/// <param name="machineName">The name of a computer on the network. </param>
		/// <exception cref="System.PlatformNotSupportedException">The operating system platform does not support this operation on remote computers. </exception>
		/// <exception cref="System.ArgumentNullException">The machineName parameter is null. </exception>
		/// <exception cref="System.InvalidOperationException">There are problems accessing the performance counter API's used to get process information. This exception is specific to Windows NT, Windows 2000, and Windows XP. </exception>
		/// <exception cref="System.ComponentModel.Win32Exception">A problem occurred accessing an underlying system API. </exception>
		/// <exception cref="System.ArgumentException">The machineName parameter syntax is invalid. It might have length zero (0). </exception>
		/// <filterpriority>1</filterpriority>
		public static Process[] GetProcessesByName(string processName, string machineName)
		{
			if (processName == null)
				processName = string.Empty;

			Process[] array = new Process[0];

			try
			{
				ArrayList list = new ArrayList();
				System.Security.Permissions.SecurityPermission s = new System.Security.Permissions.SecurityPermission(System.Security.Permissions.PermissionState.Unrestricted);
				s.Demand();
				Process[] processes = System.Diagnostics.Process.GetProcesses();
				for (int i = 0; i < processes.Length; i++)
				{
					try
					{
						if (string.Equals(processName, processes[i].ProcessName, StringComparison.OrdinalIgnoreCase))
							list.Add(processes[i]);
					}
					catch { }
				}

				array = new Process[list.Count];
				list.CopyTo(array, 0);
			}
			catch { }

			return array;
		}

	}

	internal static class NativeMethods
	{
		public const int HWND_BROADCAST = 0xffff;
		public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
		[DllImport("user32")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
		[DllImport("user32")]
		public static extern int RegisterWindowMessage(string message);
	}
}